#include "../header.h"
#include <mpi.h>

double **DataExchange(double **data, int x_points,int size,int rank) {
  MPI_Status stat;
  int i,j;
  double *temp;

  temp = (double *)malloc((ysteps-2)*sizeof(double));

  switch (rank) {
    case 0:
      for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][x_points];
      MPI_Send(temp, ysteps-1, MPI_DOUBLE, 1, TAG, MPI_COMM_WORLD);
      MPI_Recv(temp, ysteps-1, MPI_DOUBLE, 1, TAG, MPI_COMM_WORLD, &stat);
      for(i=1;i<ysteps-1;++i) data[i][x_points+1] = temp[i-1];
      break;
    default:
    if(rank == size-1) {
      if((size-1)%2 == 0) {
        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][0] = temp[i-1];        
      } else {
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][0] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, size-2, TAG, MPI_COMM_WORLD);        
      }
    } else {
      if(rank%2 == 0) {
        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][x_points];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][x_points+1] = temp[i-1];

        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD);
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][0] = temp[i-1];
      } else { 
        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][0] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][1];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank-1, TAG, MPI_COMM_WORLD);        

        MPI_Recv(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD, &stat);
        for(i=1;i<ysteps-1;++i) data[i][x_points+1] = temp[i-1];
        for(i=1;i<ysteps-1;++i) temp[i-1] = data[i][x_points];
        MPI_Send(temp, ysteps-1, MPI_DOUBLE, rank+1, TAG, MPI_COMM_WORLD);        
      }
      }
      break;
  }
  return data;
}

double **GetBoundData(double **NewData,double **OldData,
                      int x_points,int size,int rank) {
  int i;
  
  for(i=0;i<x_points+2;++i) {
    NewData[0][i] = OldData[0][i];
    NewData[(int)(ysteps-1)][i] = OldData[(int)(ysteps-1)][i];
  }
  if(rank == 0) {
    for(i=0;i<ysteps;++i) NewData[i][0] = OldData[i][0];
  } else if (rank == size-1) {
    for(i=0;i<ysteps;++i) NewData[i][x_points+1] = OldData[i][x_points+1];
  }
  return NewData;
}
